import socket, ipaddr
import sys, getopt
from SUP_message import sup_msg
import time

#Module to generate UDP packets to find SIXNET devices on a network

timeout = 1 #timeout in seconds to wait for a reply
SIXNET_port = 1594
discovery_message = "7d1cf2f0c077d01e0100636174202f70726f632f636d646c696e65001d0f"
info_message = "7d0cfff0c0000c80000000081d0f"
read_some_input = "7d1cf0ffc0000180000000087fff7fff37ea6adc00000000000000001d0f"

def send_command(ip,command):
    """Encodes a shell command, sends it to the given ip, and returns the response"""
    pkt = sup_msg()
    pkt.shell_command(command)
    return send_msg(pkt.create(),ip,SIXNET_port,4)

def tcp_send_msg(message, address = "255.255.255.255", port = SIXNET_port):
    #TODO: Make this work
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((address, port))
    
    sock.sendall(message.decode("hex"))
    data = sock.recv(2048)
    sock.close()
    return data

def send_msg(message, address = "255.255.255.255", port = SIXNET_port, tmout = 1):
    """Sends a UDP packet to the specified address on the sixnet port with a Sixnet Universal Protocol formatted message as it contents
    returns a sup_msg object if one is received, -1 otherwise"""
    
    #                     internet        UDP
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.settimeout(tmout)
    #           converts the message from ASCII representation of hex into actual real-life for-realsies hex
    sock.sendto(message.decode("hex"), (address, port))

    retdata = None

    while(retdata == None):
        try:
            retdata, addr = sock.recvfrom(2048) #buffer is 1024
        except:
            socket.timeout
            break
    
    if(retdata):
        return sup_msg(retdata.encode("hex"))
        
    else:
        return -1

def NOP_scan(address):
    """Sends a NOP command to the host if a single one is specified or every host on the network"""
    
    valid_addresses = []

    pkt = sup_msg()
    pkt.nop()

    #if this there is a / then it is a network address
    #ex: 192.168.1.0/24
    if (address.find("/") == -1):
        subnet  = False
        address = ipaddr.IPv4Address(address)
    else:
        subnet  = True
        address = ipaddr.IPv4Network(address)
    
    #if it is an address then just send that address a NOP
    if(not subnet):
        print ("Checking " + address.compressed + "  ...")
        
        reply = send_msg(pkt.create(), address.compressed)
        
        if(reply != -1):
            print ("Device found!")
            valid_addresses.append(address.compressed)
        else:
            print ("No response")
    #otherwise send one to each address in the subnet
    else:
        for host in address.iterhosts():
            print ("\rChecking " + host.compressed + "  ...")
            reply = send_msg(pkt.create(), host.compressed)

            if(reply != -1):
                print ("device found!")
                valid_addresses.append(host.compressed)

    return valid_addresses

if __name__ == "__main__":
    find(sys.argv[1:])


